/**
Copyright Christiaan Ottow 2009
chris@6core.net

See README for info
 
 This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program.  If not, see <http://www.gnu.org/licenses/>.
*/
package visim;

import java.util.regex.*;
import java.io.*;
import java.util.*;

public class ConfigReader
{
	
	private Pattern host_pat;
	private Pattern port_pat;
	private Pattern get_pat;
	private Pattern post_pat;
	private Pattern runtime_pat;
	private Pattern tag_pat;
	private Pattern crit_pat;
	private Pattern wait_pat;
	private Pattern num_pat;
	private Pattern addr_pat;
	private Pattern numaddr_pat;
	private Pattern log_pat;
	
	private Vector<Pattern> patterns;
	
	private Visim target;
	
	public ConfigReader( Visim target )
	{
		this.patterns = new Vector<Pattern>();
		
		this.target = target;
		
		tag_pat			= Pattern.compile("^testname\\s+(.*)$", Pattern.CASE_INSENSITIVE );
		host_pat 		= Pattern.compile("^host\\s+(\\S+)$", Pattern.CASE_INSENSITIVE );
		port_pat		= Pattern.compile("^port\\s+(\\d+)$", Pattern.CASE_INSENSITIVE );
		get_pat			= Pattern.compile("^get\\s+(\\S+)$", Pattern.CASE_INSENSITIVE );
		post_pat		= Pattern.compile("^post\\s+(\\S+)\\s+(\\S+)$", Pattern.CASE_INSENSITIVE );
		runtime_pat		= Pattern.compile("^runtime\\s+(\\d+)(\\w)$", Pattern.CASE_INSENSITIVE );
		crit_pat		= Pattern.compile("^require\\s+(\\d*\\.?\\d+)%\\s+(\\d+)(\\w)$", Pattern.CASE_INSENSITIVE );
		wait_pat		= Pattern.compile("^wait\\s+(\\d+)(\\w)$", Pattern.CASE_INSENSITIVE );
		num_pat			= Pattern.compile("^numclients\\s+(\\d+)$", Pattern.CASE_INSENSITIVE );
		addr_pat		= Pattern.compile("^LocalAddressStart\\s+(\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}\\.\\d{1,3})$", Pattern.CASE_INSENSITIVE );
		numaddr_pat		= Pattern.compile("^NumLocalAddresses\\s+(\\d+)$", Pattern.CASE_INSENSITIVE );
		log_pat			= Pattern.compile("^SaveResponses\\s+(\\S+)$", Pattern.CASE_INSENSITIVE );
		
		patterns.add( tag_pat );
		patterns.add( host_pat );
		patterns.add( port_pat );
		patterns.add( get_pat );
		patterns.add( post_pat );
		patterns.add( runtime_pat );
		patterns.add( tag_pat );
		patterns.add( crit_pat );
		patterns.add( wait_pat );
		patterns.add( num_pat );
		patterns.add( addr_pat );
		patterns.add( numaddr_pat );
		patterns.add( log_pat );
		
	}
	
	public boolean readFile( String filename )
	{
		File f = null;
		BufferedReader br = null;
		
		Vector<String> getRequests = new Vector<String>();
		TreeMap<String,String> postRequests = new TreeMap<String,String>();
		TreeMap<Float,Integer> requirements = new TreeMap<Float,Integer>();
		
		try {
			f = new File( filename );
			br = new BufferedReader( new InputStreamReader( new FileInputStream( f ) ) );
			String line;
			Matcher m;
			
			while( (line = br.readLine() ) != null )
			{
				for( Pattern p : this.patterns )
				{
					m = p.matcher( line );
					if( m.matches() )
					{
						if( p == this.tag_pat )
						{
							target.setTag( m.group(1) );
						} else if( p == this.host_pat ) {
							target.setHost( m.group(1) );
						} else if( p == this.port_pat ) {
							target.setPort( Integer.parseInt( m.group(1) ) );
						} else if( p == this.get_pat ) {
							getRequests.add( m.group(1) );
						} else if( p == this.post_pat ) {
							postRequests.put( m.group(1), m.group(2) );
						} else if( p == this.runtime_pat ) {
							target.setRuntime( this.toMsec( Integer.parseInt(m.group(1)), m.group(2).charAt(0) ) );
						} else if( p == this.wait_pat ) {
							target.setWait( this.toMsec( Integer.parseInt( m.group(1) ), m.group(2).charAt(0) ) );
						} else if( p == this.crit_pat ) {
							requirements.put( new Float( Float.parseFloat(  m.group( 1 ))), new Integer( (int)toMsec( Integer.parseInt( m.group(2) ), m.group(3).charAt(0) ) ) );
						} else if( p == this.num_pat ) {
							int num = Integer.parseInt( m.group(1) );
							if( num > Visim.THREAD_MAX )
							{
								System.err.println( "Only up to "+Visim.THREAD_MAX+" concurrent clients are supported. Using this value instead of "+num);
								num = Visim.THREAD_MAX;
							}
							target.setNumClients( num );
						} else if( p == this.addr_pat ) {
							target.setLocalAddress( m.group(1) );
						} else if( p == this.numaddr_pat ) {
							target.setNumAddresses( Integer.parseInt( m.group(1) ) );
						} else if( p == this.log_pat ) {
							String do_log = m.group(1);
							target.setResponseLogging( do_log.toLowerCase().equals("yes") );
						} else {
							System.err.println( "Cannot understand config line: "+line );
						}
					}
				}
			}
			br.close();
		} catch( IOException e ) {
			System.err.println("Couldn't open config file "+filename+". You may specify a config file as argument.");
			return false;
		}
		
		target.setGetRequests( getRequests );
		target.setPostRequests( postRequests );
		target.setRequirements( requirements );
		return true;
	}
	
	public long toMsec( int val, char unit )
	{
		long ret = val * 1000;
		if( unit == 's' )
		{
			return ret;
		}
		ret *= 60;
		if( unit == 'm' )
		{
			return ret;
		}
		ret *= 60;
		if( unit == 'h' )
		{
			return ret;
		}
		ret *= 24;
		
		// ret is now msecs in days
		return ret;
	}
}

	